#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/times.h>
#include <semaphore.h>
#include <fcntl.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <regex.h>
#include <stdbool.h>
#include "ImageType.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

struct yaml_key_val_pair
{
  long long shm_size;
  long long shm_num;
  char** shm_key_array;
};

struct yaml_input_struct
{
  char input_data[50];
  long input_data_ptr;
};

bool isNumber(char c)
{
  switch(c)
  {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      return true;
    break;
    default:
    return false;
  }
}

char* GetStringFromYamlArray(const char* str)
{
  char buffer[50];
  memset(buffer,0x0,50);
  int ptr=0;
  //跳过-和空白字符
  while(true)
  {
    if(str[ptr]=='-' || str[ptr]==' ')
      ptr++;
    else if(str[ptr]=='\n' || str[ptr]=='\0')
    {
      printf("无法搜到数组,请检查文件是否正确");
      exit(-1);
    }
    else
      break;
  }
  //获取字符串
  int buffer_ptr=0;
  while(true)
  {
    if(str[ptr]=='\n' || str[ptr]==' ' || str[ptr]=='\0')
      break;
    else
    {
      buffer[buffer_ptr]=str[ptr];
      buffer_ptr++;
    }
    ptr++;
  }
  //分配新的内存
  char* retStr=malloc(buffer_ptr+1);
  memset(retStr,0x0,buffer_ptr+1);
  memcpy(retStr,buffer,buffer_ptr);
  return retStr;
}

long long GetNumFromStr(const char* str)
{
  char cal_data[50];
  memset(cal_data,0x0,50);
  int ptr=0;
  int cal_data_ptr=0;
  //去除开头空白
  while(true)
  {
    if(isNumber(str[ptr]))
    {
      break;
    }
    else ptr++;
  }
  //读取数据
  while(true)
  {
    if(isNumber(str[ptr]))
    {
        cal_data[cal_data_ptr]=str[ptr];
        cal_data_ptr++;
        ptr++;
    }
    else
    {
      break;
    }
  }
  //返回数字
  return atoll(cal_data);
}

size_t dumpPtrToNextLine(const char* data,size_t ptr)
{
  while(true)
  {
    if(data[ptr]=='\n' || data[ptr]=='\0') break;
    else ptr++;
  }
  return ptr;
}

struct yaml_key_val_pair extract_data_from_yaml(const char* data,size_t size)
{
  struct yaml_key_val_pair new_yaml;
  struct yaml_input_struct input_yaml;
  memset(&input_yaml,0x0,sizeof(input_yaml));

  for(int data_ptr=0;data_ptr<size;data_ptr++)
  {
    switch(data[data_ptr])
    {
      case ':':
      {
        if(strcmp(input_yaml.input_data,"shm_size")==0)
        {
          new_yaml.shm_size=GetNumFromStr(&(data[data_ptr+1]));
          data_ptr=dumpPtrToNextLine(data,data_ptr);
        }
        else if(strcmp(input_yaml.input_data,"num")==0)
        {
          new_yaml.shm_num=GetNumFromStr(&(data[data_ptr+1]));
          data_ptr=dumpPtrToNextLine(data,data_ptr);
        }
        else if(strcmp(input_yaml.input_data,"shm")==0)
        {
          new_yaml.shm_key_array=malloc(sizeof(char*)*new_yaml.shm_num);
          data_ptr=dumpPtrToNextLine(data,data_ptr)+1;
          for(int j=0;j<new_yaml.shm_num;j++)
          {
            new_yaml.shm_key_array[j]=GetStringFromYamlArray(data+data_ptr);
            data_ptr=dumpPtrToNextLine(data,data_ptr)+1;
          }
        }
        else
        //乱七八糟的属性
        {
          printf("unknow yaml key\n");
          exit(-1);
        }
        //清空一下
        memset(&input_yaml,0x0,sizeof(input_yaml));
      }
      break;

      case '\n':
      break;

      default:
      {
        input_yaml.input_data[input_yaml.input_data_ptr]=data[data_ptr];
        input_yaml.input_data_ptr++;
        if(input_yaml.input_data_ptr>=50)
        //安全检查
        {
          printf("yaml data too big\n");
          exit(-1);
        }
      }
    }
  }
  return new_yaml;
}

size_t GetFileAllData(const char* filePath,char* buffer,size_t size)
{
  int InputShareMem_fd=open(filePath,O_RDONLY);
  if(InputShareMem_fd==-1)
  {
    printf("Can't open config file");
    exit(-1);
  }
  memset(buffer,0,size);
  int read_size=0;
  int lastReadBufferSize=size;
  char* readPosition=buffer;
  do
  {
    read_size=read(InputShareMem_fd,readPosition,lastReadBufferSize);
    if(read_size==-1)
    {
      printf("Can't read yaml file data\n");
      exit(-1);
    }
    readPosition+=read_size;
    lastReadBufferSize-=read_size;
    if(lastReadBufferSize<=1)
    {
      printf("The buffer is full, yaml file is too large\n");
      exit(-1);
    }
  }
  while(read_size!=0);
  close(InputShareMem_fd);
  return readPosition-(char*)buffer;
}

char* InitSharedMem(const char* memName,size_t memSize)
{
  int fd=shm_open(memName,O_EXCL | O_RDWR,0);
  if(fd==-1)
  {
    printf("无法打开共享内存 %s\n",memName);
    exit(-1);
  }
  char* mem=mmap(NULL,memSize,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
  if(mem==MAP_FAILED)
  {
      printf("无法创建共享内存映射");
      exit(-1);
  }
  close(fd);
  return mem;
}

char* OpenSharedMem(const char* memName,size_t memSize)
{
  int fd=shm_open(memName,O_CREAT | O_RDWR,S_IRUSR | S_IWUSR);
  if(fd==-1)
  {
    printf("无法打开共享内存 %s\n",memName);
    exit(-1);
  }
  if(ftruncate(fd,memSize)==-1)
  {
    printf("无法设置共享内存大小\n");
    exit(-1);
  }
  char* mem=mmap(NULL,memSize,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
  if(mem==MAP_FAILED)
  {
      printf("无法创建共享内存映射");
      exit(-1);
  }
  close(fd);
  return mem;
}

void DeleteSharedMem(char* sm)
{

}

sem_t* InitSem(const char* name)
{
  sem_t* val=sem_open(name,O_EXCL | O_RDWR);
  if(val==SEM_FAILED)
  {
    printf("无法打开信号量 %s\n",name);
    exit(-1);
  }
  return val;
}

sem_t* OpenSem(const char* name)
{
  sem_t* val=sem_open(name,O_CREAT | O_RDWR,S_IRUSR | S_IWUSR,1);
  if(val==SEM_FAILED)
  {
    printf("无法打开信号量 %s\n",name);
    exit(-1);
  }
  int value;
  sem_getvalue(val,&value);
  printf("信号量初值为： %d\n",value);
  if(value!=1)
    sem_post(val);
  return val;
}

void LockSem(sem_t* sem)
{
  if(sem_wait(sem)==-1)
  {
    printf("无法给信号量加锁\n");
    exit(-1);
  }
}

void UnlockSem(sem_t* sem)
{
  if(sem_post(sem)==-1)
  {
    printf("无法给信号量解锁\n");
    exit(-1);
  }
}

struct IPCinf
{
  char** shareMemList;
  size_t shareMemNum;
  sem_t* sem;
};

struct OutputIPCInf
{
  char* shareMemNum;
  sem_t* sem;
};

const char* outputSharedMemoryName="/HBTY_HANDLE_SHAREDMEM";
const char* outputSemaphoreName="/HBTY_HANDLE_SEMAPHORE";

int main()
{
  //程序初始化
  //获取配置文件
  struct yaml_key_val_pair input_ipc_para;
  {
    char fileData[512];
    size_t allDataSize=GetFileAllData("/tmp/HBTY_server_ipc.yaml",fileData,sizeof(fileData));
    input_ipc_para=extract_data_from_yaml(fileData,allDataSize);
  }

  //准备输入IPC
  struct IPCinf inputIPCInf;

  //共享内存准备
  inputIPCInf.shareMemNum=input_ipc_para.shm_num;
  inputIPCInf.shareMemList=malloc(sizeof(char*)*input_ipc_para.shm_num);
  for(int i=0;i<inputIPCInf.shareMemNum;i++)
    inputIPCInf.shareMemList[i]=InitSharedMem(input_ipc_para.shm_key_array[i],input_ipc_para.shm_size);

  //信号量准备
  //inputIPCInf.sem=InitSem("/HBTY_ORIMAGE_SEMAPHORE");

  //准备输出IPC
  struct OutputIPCInf outputIPCInf;
  outputIPCInf.shareMemNum=OpenSharedMem(outputSharedMemoryName,input_ipc_para.shm_size-sizeof(struct ImageType));
  outputIPCInf.sem=OpenSem(outputSemaphoreName);
  
  //初始化数据对象
  char* imageData[5];
  //对小于5张图的剩下部分进行补充
  for(int i=inputIPCInf.shareMemNum;i<5;i++)
  {
    imageData[i]=malloc(input_ipc_para.shm_size);
    memset(imageData[i],0x0,input_ipc_para.shm_size);
  }
  //然后分配内存
  for(int i=0;i<inputIPCInf.shareMemNum;i++)
    imageData[i]=malloc(input_ipc_para.shm_size);

  //初始化python
  Py_Initialize();
  PyRun_SimpleString(
    "import sys\n"
    "import os\n"
    "sys.path.append(\"/home/hbty/Kps2Smpl\")\n"
    "os.getcwd()\n"
  );

  /*
  //导入模块
  PyObject* sysModuleName=PyUnicode_DecodeFSDefault("sys");
  PyObject* sysModule=PyImport_Import(sysModuleName);
  Py_DecRef(sysModuleName);
  if(sysModule==NULL)
  {
    printf("Can't import sys module");
    exit(-1);
  }
  PyObject* sysPathAppendFunc=PyObject_GetAttrString(sysModule,"sys.path.append");
  if(!sysPathAppendFunc || !PyCallable_Check(sysPathAppendFunc))
  {
    printf("Can't get sys.path.append func");
    exit(-1);
  }
  PyObject* sysPathAppendFuncArg=PyTuple_New(1);
  PyObject* sysPathAppendFuncArg_1=PyUnicode_DecodeFSDefault("/home/A306/HBTY/SimpleAlphapose");
  PyTuple_SetItem(sysPathAppendFuncArg,0,sysPathAppendFuncArg_1);
  PyObject_CallObject(sysPathAppendFunc,sysPathAppendFuncArg);
  Py_DecRef(sysPathAppendFuncArg_1);
  Py_DecRef(sysPathAppendFuncArg);
  */
  //导入test
  PyObject* testModuleName=PyUnicode_DecodeFSDefault("run");
  PyObject* testModule=PyImport_Import(testModuleName);
  if(!testModule)
  {
    printf("Can't load testModule\n");
    PyErr_Print();
    exit(-1);
  }
  Py_DecRef(testModuleName);
  PyObject* testWorkFunc=PyObject_GetAttrString(testModule,"callme");
  if(!testWorkFunc || !PyCallable_Check(testWorkFunc))
  {
    printf("Can't get callme func\n");
    PyErr_Print();
    exit(-1);
  }
  Py_DecRef(testModuleName);

  long time_unit_size=sysconf(_SC_CLK_TCK);
  //处理循环
  while(true)
  {
    //Clock
    // {
    //   struct tms time_res;
    //   clock_t abstime=times(&time_res);
    //   printf("Absolute time %lf,User CPU time used by caller %lf , User CPU time of all children %lf\n",(double)abstime/time_unit_size,(double)time_res.tms_utime/time_unit_size,(double)time_res.tms_cutime/time_unit_size);
    // }

    //获取数据
    {
      //LockSem(inputIPCInf.sem);
      //for(int i=0;i<inputIPCInf.shareMemNum;i++)
      //  memcpy(imageData[i],inputIPCInf.shareMemList[i],input_ipc_para.shm_size);
      memcpy(imageData[0],inputIPCInf.shareMemList[2],input_ipc_para.shm_size);
      //UnlockSem(inputIPCInf.sem);
    }
    //导出获取的数据
    /*
    {
      int ret;
      int saveFileFD=open("./data",O_CREAT | O_TRUNC | O_RDWR,S_IRWXU);
      if(saveFileFD==-1)
      {
        printf("Can't open output file");
        exit(-1);
      }
      int finishWriteSize=0;
      while(finishWriteSize<input_ipc_para.shm_size)
      {
        int writeSize=write(saveFileFD,imageData[0]+inp    cv2.imwrite("output.jpg",results["Image"][0])ut_ipc_para.shm_size,input_ipc_para.shm_size-finishWriteSize);
        if(writeSize==-1)
        {
          printf("Can't write data into file");
          exit(-1);
        }
        finishWriteSize=writeSize;
      }
      close(saveFileFD);
    }

    */
    //Python调用
    {
      //准备参数
      /*
      PyObject* dataList=PyList_New(5);
      for(int i=0;i<5;i++)
      {
        PyObject* imageBytes=PyBytes_FromStringAndSize((imageData[i])+sizeof(struct ImageType),input_ipc_para.shm_size-sizeof(struct ImageType));
        PyList_SetItem(dataList,i,imageBytes);
      }
      PyObject* funcArg=PyTuple_New(1);
      PyTuple_SetItem(funcArg,0,dataList);
       * */
      PyObject* dataList=PyList_New(1);
      PyObject* imageBytes=PyBytes_FromStringAndSize((imageData[0])+sizeof(struct ImageType),input_ipc_para.shm_size-sizeof(struct ImageType));
      PyList_SetItem(dataList,0,imageBytes);
      PyObject* funcArg=PyTuple_New(1);
      PyTuple_SetItem(funcArg,0,dataList);
      //发起调用
      PyObject* result=PyObject_CallObject(testWorkFunc,funcArg);
      if(result==NULL)
      {
        printf("Can't call this function\n");
        PyErr_Print();
        exit(-1);
      }
      //获得结果
      if(PyBytes_Check(result))
      {
        Py_ssize_t resSize;
        char* pBuffer;
        if(PyBytes_AsStringAndSize(result,&pBuffer,&resSize)==-1)
          printf("Get result data failed\n");
        //stbi_write_bmp("c_output.png",1920,1080,3,pBuffer);
        LockSem(outputIPCInf.sem);
        memcpy(outputIPCInf.shareMemNum,pBuffer,1920*1080*3);
        UnlockSem(outputIPCInf.sem);
      }
      Py_DecRef(result);
      Py_DecRef(funcArg);

    }
    //输出数据
  }

  //释放资源

  return 0;
}
